/*-
 * PDUElementText.java
 *
 * $LastChangedBy:  $
 * $LastChangedRevision:  $
 * $LastChangedDate:  $
 * $HeadURL: $
 *
 * Copyright (c) 2008, Stein Gunnar Bakkeby
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Stein Gunnar Bakkeby nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.googlecode.attention.sms.pdu;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;

import static com.googlecode.attention.sms.pdu.PDUElement.*;

public class PDUElementText {
  
  private static Map<String, String> textMap = new HashMap<String, String>();
  
  static {
    final ResourceBundle rb = ResourceBundle.getBundle(
        "com.googlecode.attention.sms.pdu.pduelements");
    final Enumeration<String> keys = rb.getKeys();
    while (keys.hasMoreElements()) {
      final String key = keys.nextElement();
      textMap.put(key, rb.getString(key));
    }
  }
  
  public static String getText(final String key, final PDUElement element) {
    /* Removes "TP_" from PDU element */
    return textMap.get(element.toString().substring(3)  + '_' + key);
  }
  
  public static String getMMSText(final TPDU tpdu) {
    return getMMSText(new FO(tpdu.get(TP_FO)));
  }
  
  public static String getMMSText(final FO fo) {
    final String key = MMS.parse(fo.get(TP_MMS)).toString();
    return getText(key, TP_MMS);
  }
  
  public static String getVPFText(final TPDU tpdu) {
    return getVPFText(VPF.parse(tpdu.get(TP_VPF)));
  }
  
  public static String getVPFText(final VPF vpf) {
    return getText(vpf.toString(), TP_VPF);
  }
  
  public static String getRPText(final TPDU tpdu) {
    return getRPText(RP.parse(tpdu.get(TP_RP)));
  }
  
  public static String getRPText(final RP rp) {
    return getText(rp.toString(), TP_RP);
  }
  
  public static String getRDText(final TPDU tpdu) {
    return getRDText(RD.parse(tpdu.get(TP_RD)));
  }
  
  public static String getRDText(final RD rd) {
    return getText(rd.toString(), TP_RD);
  }
  
  public static String getSRIText(final TPDU tpdu) {
    return getSRIText(SRI.parse(tpdu.get(TP_SRI)));
  }
  
  public static String getSRIText(final SRI sri) {
    return getText(sri.toString(), TP_SRI);
  }
  
  public static String getSRRText(final TPDU tpdu) {
    return getSRRText(SRR.parse(tpdu.get(TP_SRR)));
  }
  
  public static String getSRRText(final SRR srr) {
    return getText(srr.toString(), TP_SRR);
  }
  
  public static String getSRQText(final TPDU tpdu) {
    return getSRQText(SRQ.parse(tpdu.get(TP_SRQ)));
  }
  
  public static String getSRQText(final SRQ srq) {
    return getText(srq.toString(), TP_SRQ);
  }
  
  public static String getMTIText(final TPDU tpdu) {
    final String key;
    final int value = tpdu.getType();
    switch (value) {
    case TPDU.SMS_DELIVER:
      key = "SMS_DELIVER";
      break;
      
    case TPDU.SMS_DELIVER_REPORT:
      key = "SMS_DELIVER_REPORT";
      break;
      
    case TPDU.SMS_SUBMIT:
      key = "SMS_SUBMIT";
      break;
      
    case TPDU.SMS_SUBMIT_REPORT:
      key = "SMS_SUBMIT_REPORT";
      break;
      
    case TPDU.SMS_STATUS_REPORT:
      key = "SMS_STATUS_REPORT";
      break;
      
    case TPDU.SMS_COMMAND:
      key = "SMS_COMMAND";
      break;
      
    default:
      key = "RESERVED";
      break;
    }
    
    return getText(key, TP_MTI);
  }
  
  public static String getTOAText(final TPDU tpdu, final String separator) {
    final Address address = tpdu.getAddress();
    return (address == null ? "" : getTOAText(address.getTOA(), separator));
  }
  
  public static String getTOAText(final TOA toa, final String separator) {
    return getTONText(toa) + separator + getNPIText(toa);
  }
  
  public static String getNPIText(final TPDU tpdu) {
    final Address address = tpdu.getAddress();
    if (address == null) return "";
    
    return getNPIText(address.getTOA());
  }
  
  public static String getVPText(final TPDU tpdu) {
    switch (tpdu.getType()) {
    case TPDU.SMS_SUBMIT:
      final SMSSubmit submit = (SMSSubmit)tpdu;
      final VP vp = submit.getValidityPeriod();
      return getVPText(vp);
      
    default:
      return "";
    }
  }
  
  public static String getVPText(final VP vp) {
    final String text;
    if (vp == null) {
      text = textMap.get("VP_NOT_PRESENT");
    } else {
      final VPF vpf = vp.getVPF();
      switch (vpf) {
      case ABSOLUTE_FORMAT:
        final SCTS abs = vp.getAbsoluteTime();
        // TODO own pattern here
        text = (abs == null ? "" : abs.getTimeStamp());
        break;
        
      case ENHANCED_FORMAT:
        final VPEnhancedTime et = vp.getEnhancedTime();
        switch (et.getFormat()) {
        case NO_VALIDITY_PERIOD_SPECIFIED:
          text = textMap.get("VP_NOT_PRESENT");
          break;
          
        case RELATIVE_TIME:
          text = getRelativeTimeText(vp);
          break;
          
        case RESERVED_100:
        case RESERVED_101:
        case RESERVED_110:
        case RESERVED_111:
          text = textMap.get("VP_RESERVED");
          break;
          
        case VALIDITY_PERIOD_0_TO_255_SECONDS:
          final int secs = et.getSeconds();
          final String secsKey = (secs == 1 ? "VP_SECOND" : "VP_SECONDS");
          text = Integer.toString(secs) + " " + textMap.get(secsKey);
          break;
          
        case VALIDITY_PERIOD_HH_MM_SS:
          final StringBuilder sb = new StringBuilder();
          String key;
          final int hours = et.getHours();
          boolean separate = false;
          if (hours > 0) {
            key = (hours == 1 ? "VP_HOUR" : "VP_HOURS");
            sb.append(hours);
            sb.append(' ');
            sb.append(textMap.get(key));
            separate = true;
          }
          
          final int minutes = et.getHours();
          if (minutes > 0) {
            if (separate) sb.append(' ');
            key = (minutes == 1 ? "VP_MINUTE" : "VP_MINUTES");
            sb.append(minutes);
            sb.append(' ');
            sb.append(textMap.get(key));
            sb.append(' ');
          }
  
          final int seconds = et.getSeconds();
          key = (seconds == 1 ? "VP_SECOND" : "VP_SECONDS");
          sb.append(seconds);
          sb.append(' ');
          sb.append(textMap.get(key));
          
          text = sb.toString();
          break;
          
        default:
          text = "";
          break;
        }
        break;
        
        
      case RELATIVE_FORMAT:
        text = getRelativeTimeText(vp);
        break;
  
      default:
      case FIELD_NOT_PRESENT:
        text = textMap.get("VP_NOT_PRESENT");
        break;
      }
    }

    return text;
  }
  
  public static String getRelativeTimeText(final VP vp) {
    final VPRelativeTime rt = vp.getRelativeTime();
    int minutes = rt.getTime();
    final StringBuilder sb = new StringBuilder();
    String key;
    boolean separate = false;
    
    if (minutes >= 10080) {
      final int weeks = minutes / 10080;
      minutes %= 10080;
      sb.append(weeks);
      sb.append(' ');
      key = (weeks == 1 ? "VP_WEEK" : "VP_WEEKS");
      sb.append(textMap.get(key));
      separate = true;
    }
    
    if (minutes >= 1440) {
      final int days = minutes / 1440;
      minutes %= 1440;
      if (separate) sb.append(' ');
      sb.append(days);
      sb.append(' ');
      key = (days == 1 ? "VP_DAY" : "VP_DAYS");
      sb.append(textMap.get(key));
      separate = true;
    }
    
    if (minutes >= 60) {
      final int hours = minutes / 60;
      minutes %= 60;
      if (separate) sb.append(' ');
      sb.append(hours);
      sb.append(' ');
      key = (hours == 1 ? "VP_HOUR" : "VP_HOURS");
      sb.append(textMap.get(key));
      separate = true;
    }
    
    if (minutes > 0) {
      if (separate) sb.append(' ');
      sb.append(minutes);
      sb.append(' ');
      key = (minutes == 1 ? "VP_MINUTE" : "VP_MINUTES");
      sb.append(textMap.get(key));
    }
    
    return sb.toString();
  }
  
  public static String getNPIText(final TOA toa) {
    final String key;
    final int value = toa.getNumPlanIdent();
    switch (value) {
    case TOA.NPI_UNKNOWN:
      key = "NPI_UNKNOWN";
      break;
      
    case TOA.NPI_ISDN:
      key = "NPI_ISDN";
      break;
      
    case TOA.NPI_DATA:
      key = "NPI_DATA";
      break;
      
    case TOA.NPI_TELEX:
      key = "NPI_TELEX";
      break;
      
    case TOA.NPI_SCSP_0101:     
    case TOA.NPI_SCSP_0110:
      key = "NPI_SCSP";
      break;
      
    case TOA.NPI_NATIONAL:
      key = "NPI_NATIONAL";
      break;
      
    case TOA.NPI_PRIVATE:
      key = "NPI_PRIVATE";
      break;
      
    case TOA.NPI_ERMES:
      key = "NPI_ERMES";
      break;
      
    case TOA.NPI_RESERVED:
      key = "NPI_RESERVED";
      break;
      
    default:
      key = "NPI_RESERVED";
      break;
    }
    
    return textMap.get("TOA_" + key);
  }
  
  public static String getTONText(final TPDU tpdu) {
    final Address address = tpdu.getAddress();
    if (address == null) return "";
    
    return getTONText(address.getTOA());
  }
  
  public static String getTONText(final TOA toa) {
    final String key;
    final int value = toa.getTypeOfNumber();
    switch (value) {
    case TOA.TON_ABBREVATED_NUMBER:
      key = "TON_ABBREVATED_NUMBER";
      break;
      
    case TOA.TON_ALPHANUMERIC:
      key = "TON_ALPHANUMERIC";
      break;
      
    case TOA.TON_INTERNATIONAL_NUMBER:
      key = "TON_INTERNATIONAL_NUMBER";
      break;
      
    case TOA.TON_NATIONAL_NUMBER:
      key = "TON_NATIONAL_NUMBER";
      break;
      
    case TOA.TON_NETWORK_SPECIFIC_NUMBER:
      key = "TON_NETWORK_SPECIFIC_NUMBER";
      break;
      
    case TOA.TON_SUBSCRIBER_NUMBER:
      key = "TON_SUBSCRIBER_NUMBER";
      break;
      
    case TOA.TON_UNKNOWN:
      key = "TON_UNKNOWN";
      break;
      
    case TOA.TON_RESERVED:
      key = "TON_RESERVED";
      break;
      
    default:
      key = "TON_RESERVED";
      break;
    }
    
    return textMap.get("TOA_" + key);
  }
  
  public static String getFCSText(final TPDU tpdu) {
    final int value = tpdu.get(TP_FCS);
    return (value == -1 ? "" : getFCSText(new FCS(value)));
  }
  
  public static String getSTText(final TPDU tpdu) {
    final int value = tpdu.get(TP_ST);
    return (value == -1 ? "" : getSTText(new ST(value)));
  }
  
  public static String getPIDText(final TPDU tpdu) {
    final int value = tpdu.get(TP_PID);
    return (value == -1 ? "" : getPIDText(new PID(value)));
  }
  
  public static String getDCSText(final TPDU tpdu, final String separator) {
    final int value = tpdu.get(TP_DCS);
    return (value == -1 ? "" : getDCSText(new DCS(value), separator));
  }
  
  public static String getCTText(final TPDU tpdu) {
    final int value = tpdu.get(TP_CT);
    return (value == -1 ? "" : getCTText(new CT(value)));
  }
  
  public static String getPIText(final TPDU tpdu, final String separator) {
    final int value = tpdu.get(TP_PI);
    return (value == -1 ? "" : getPIText(new PI(value), separator));
  }
  
  public static String getUDHIText(final TPDU tpdu) {
    final int value = tpdu.get(TP_UDHI);
    return (value == -1 ? "" : getUDHIText(UDHI.parse(value)));
  }
  
  public static String getUDHIText(final UDHI udhi) {
    final String key;
    switch (udhi) {
    case HEADER_PRESENT:
      key = "HEADER_PRESENT";
      break;
      
    default:
    case SHORT_MESSAGE_ONLY:
      key = "HEADER_NOT_PRESENT";
      break;
    }
    
    return getText(key, TP_UDHI);
  }
  
  public static String getFOText(final TPDU tpdu, final String separator) {
    final StringBuilder sb = new StringBuilder();
    switch (tpdu.getType()) {
    case TPDU.SMS_DELIVER:
      sb.append(getRPText(tpdu));
      sb.append(separator);
      sb.append(getUDHIText(tpdu));
      sb.append(separator);
      sb.append(getSRIText(tpdu));
      sb.append(separator);
      sb.append(getMMSText(tpdu));
      sb.append(separator);
      sb.append(getMTIText(tpdu));
      break;
      
    case TPDU.SMS_SUBMIT:
      sb.append(getRPText(tpdu));
      sb.append(separator);
      sb.append(getUDHIText(tpdu));
      sb.append(separator);
      sb.append(getSRRText(tpdu));
      sb.append(separator);
      sb.append(getVPFText(tpdu));
      sb.append(separator);
      sb.append(getRDText(tpdu));
      sb.append(separator);
      sb.append(getMTIText(tpdu));
      break;
      
    case TPDU.SMS_COMMAND:
      sb.append(getUDHIText(tpdu));
      sb.append(separator);
      sb.append(getSRRText(tpdu));
      sb.append(separator);
      sb.append(getMTIText(tpdu));
      break;
      
    case TPDU.SMS_DELIVER_REPORT:
      sb.append(getUDHIText(tpdu));
      sb.append(separator);
      sb.append(getMTIText(tpdu));
      break;
      
    case TPDU.SMS_SUBMIT_REPORT:
      sb.append(getUDHIText(tpdu));
      sb.append(separator);
      sb.append(getMTIText(tpdu));
      break;
      
    case TPDU.SMS_STATUS_REPORT:
      sb.append(getUDHIText(tpdu));
      sb.append(separator);
      sb.append(getSRQText(tpdu));
      sb.append(separator);
      sb.append(getMMSText(tpdu));
      sb.append(separator);
      sb.append(getMTIText(tpdu));
      break;
      
    default:
      break; 
    }
    return sb.toString();
  }
  
  public static String getPIText(final PI pi, final String separator) {
    final StringBuilder sb = new StringBuilder();
    String key;
    String text;
    boolean separate = false;
    key = pi.isExtensionOctetIndicated() ? "PI_EXTENSION_OCTET_INDICATED"
                                         : "PI_EXTENSION_OCTET_NOT_INDICATED"; 
    text = textMap.get(key);
    if (text.length() > 0) {
      if (separate) sb.append(separator);
      sb.append(text);
      separate = true;
    }
    
    key = pi.isReservedIndicated() ? "PI_RESERVED_OCTET_INDICATED"
                                   : "PI_RESERVED_OCTET_NOT_INDICATED"; 
    text = textMap.get(key);
    if (text.length() > 0) {
      if (separate) sb.append(separator);
      sb.append(text);
      separate = true;
    }
    
    key = pi.isUDLIndicated() ? "PI_UDL_OCTET_INDICATED"
                              : "PI_UDL_OCTET_NOT_INDICATED"; 
    text = textMap.get(key);
    if (text.length() > 0) {
      if (separate) sb.append(separator);
      sb.append(text);
      separate = true;
    }
    
    key = pi.isDCSIndicated() ? "PI_DCS_OCTET_INDICATED"
                              : "PI_DCS_OCTET_NOT_INDICATED"; 
    text = textMap.get(key);
    if (text.length() > 0) {
      if (separate) sb.append(separator);
      sb.append(text);
      separate = true;
    }
    
    key = pi.isPIDIndicated() ? "PI_PID_OCTET_INDICATED"
                              : "PI_PID_OCTET_NOT_INDICATED"; 
    text = textMap.get(key);
    if (text.length() > 0) {
      if (separate) sb.append(separator);
      sb.append(text);
      separate = true;
    }
    
    return sb.toString();
  }
  
  public static String getCTText(final CT ct) {
    final int value = ct.getValue();
    final String key;
    switch (value) {
    case CT.ENQUIRY_RELATING_TO_PREVIOUSLY_SUBMITTED_SM:
      key = "ENQUIRY_RELATING_TO_PREVIOUSLY_SUBMITTED_SM";
      break;
      
    case CT.CANCEL_STATUS_REPORT_REQUEST:
      key = "CANCEL_STATUS_REPORT_REQUEST";
      break;
      
    case CT.DELETE_PREVIOUSLY_SUBMITTED_SM:
      key = "DELETE_PREVIOUSLY_SUBMITTED_SM";
      break;
      
    case CT.ENABLE_STATUS_REPORT_REQUEST:
      key = "ENABLE_STATUS_REPORT_REQUEST";
      break;
      
    default:
      if (value >= 4 && value <= 31) {
        key = "RESERVED";
      } else if (value >= 224 && value <= 255) {
        key = "SC_SPECIFIC";
      } else {
        key = "UNKNOWN";
      }
    }
    return getText(key, TP_CT);
  }
  
  public static String getDCSText(final DCS dcs, final String separator) {
    final StringBuilder sb = new StringBuilder(); 
    switch (dcs.getGroup()) {
    case DCS.GROUP_AUTOMATIC_DELETION:
      sb.append(textMap.get("DCS_GROUP_AUTOMATIC_DELETION"));
      sb.append(separator);
      /* falls through */
      
    case DCS.GROUP_GENERAL_DATA_CODING:
      if (dcs.isTextCompressed()) {
        sb.append(textMap.get("DCS_COMPRESSED_TEXT"));
      } else {
        sb.append(textMap.get("DCS_UNCOMPRESSED_TEXT"));
      }
      /* falls through*/
      
    case DCS.GROUP_MESSAGE_CODING_CLASS:
      if (dcs.getGroup() == DCS.GROUP_MESSAGE_CODING_CLASS) {
        sb.append(textMap.get("DCS_GROUP_MESSAGE_CODING_CLASS"));
      }
      sb.append(separator);
      
      switch (dcs.getMessageCoding()) {
      case DCS.MESSAGE_CODING_7_BIT_DEFAULT:
        sb.append(textMap.get("DCS_MESSAGE_CODING_7_BIT_DEFAULT"));
        break;
        
      case DCS.MESSAGE_CODING_8_BIT_DATA:
        sb.append(textMap.get("DCS_MESSAGE_CODING_8_BIT_DATA"));
        break;
        
      case DCS.MESSAGE_CODING_UCS2:
        sb.append(textMap.get("DCS_MESSAGE_CODING_UCS2"));
        break;

      case DCS.MESSAGE_CODING_RESERVED:
        sb.append(textMap.get("DCS_MESSAGE_CODING_RESERVED"));
        break;
      }
      
      if (dcs.hasClassMeaning()) {
        sb.append(separator);
        switch (dcs.getClassMeaning()) {
        case DCS.MESSAGE_CLASS_0:
          sb.append(textMap.get("DCS_MESSAGE_CLASS_0"));
          break;
          
        case DCS.MESSAGE_CLASS_1:
          sb.append(textMap.get("DCS_MESSAGE_CLASS_0"));
          break;
          
        case DCS.MESSAGE_CLASS_2:
          sb.append(textMap.get("DCS_MESSAGE_CLASS_0"));
          break;
          
        case DCS.MESSAGE_CLASS_3:
          sb.append(textMap.get("DCS_MESSAGE_CLASS_0"));
          break;
        }
      }
      break;
      
    case DCS.GROUP_MESSAGE_WAITING_DISCARD:
    case DCS.GROUP_MESSAGE_WAITING_STORE:
    case DCS.GROUP_MESSAGE_WAITING_STORE_UCS2:
      switch (dcs.getGroup()) {
      case DCS.GROUP_MESSAGE_WAITING_DISCARD:
        sb.append(textMap.get("DCS_GROUP_MESSAGE_WAITING_DISCARD"));
        break;
        
      case DCS.GROUP_MESSAGE_WAITING_STORE:
        sb.append(textMap.get("DCS_GROUP_MESSAGE_WAITING_STORE"));
        break;
        
      case DCS.GROUP_MESSAGE_WAITING_STORE_UCS2:
        sb.append(textMap.get("DCS_GROUP_MESSAGE_WAITING_STORE_UCS2"));
        break;
      }
      
      sb.append(separator);
      
      if (dcs.isIndicationActive()) {
        sb.append(textMap.get("DCS_WAITING_SET_INDICATION_ACTIVE"));
      } else {
        sb.append(textMap.get("DCS_WAITING_SET_INDICATION_INACTIVE"));
      }
      
      sb.append(separator);
      
      switch (dcs.getGroup()) {
      case DCS.GROUP_MESSAGE_WAITING_DISCARD:
      case DCS.GROUP_MESSAGE_WAITING_STORE:
        sb.append(textMap.get("DCS_MESSAGE_CODING_7_BIT_DEFAULT"));
        break;
        
      case DCS.GROUP_MESSAGE_WAITING_STORE_UCS2:
        sb.append(textMap.get("DCS_MESSAGE_CODING_UCS2"));
        break;
      }
      
      sb.append(separator);
      
      switch (dcs.getIndicationType()) {
      case DCS.MESSAGE_WAITING_VOICEMAIL:
        sb.append(textMap.get("DCS_MESSAGE_WAITING_VOICEMAIL"));
        break;
        
      case DCS.MESSAGE_WAITING_FAX:
        sb.append(textMap.get("DCS_MESSAGE_WAITING_FAX"));
        break;
        
      case DCS.MESSAGE_WAITING_ELECTRONIC_MAIL:
        sb.append(textMap.get("DCS_MESSAGE_WAITING_ELECTRONIC_MAIL"));
        break;
        
      default:
      case DCS.MESSAGE_WAITING_OTHER:
        sb.append(textMap.get("DCS_MESSAGE_WAITING_OTHER"));
        break;
      }
      break;
      
    case DCS.GROUP_RESERVED_1000:
    case DCS.GROUP_RESERVED_1001:
    case DCS.GROUP_RESERVED_1010:
    case DCS.GROUP_RESERVED_1011:
    default:
      sb.append(textMap.get("DCS_GROUP_RESERVED"));
      break;
    }
    
    return sb.toString();
  }
  
  public static String getPIDText(final PID pid) {
    final String key;
    final int group = pid.getGroup();
    switch (group) {
    case PID.GROUP_TI:
      switch (pid.getValue()) {
      case PID.TI_IMPLICIT:
        key = "TI_IMPLICIT";
        break;
        
      case PID.TI_TELEX:
        key = "TI_TELEX";
        break;
        
      case PID.TI_TELEFAX_GROUP_3:
        key = "TI_TELEFAX_GROUP_3";
        break;
        
      case PID.TI_TELEFAX_GROUP_4:
        key = "TI_TELEFAX_GROUP_4";
        break;
        
      case PID.TI_VOICE_TELEPHONE:
        key = "TI_VOICE_TELEPHONE";
        break;
        
      case PID.TI_ERMES:
        key = "TI_ERMES";
        break;
        
      case PID.TI_NATIONAL_PAGING_SYSTEM:
        key = "TI_NATIONAL_PAGING_SYSTEM";
        break;
        
      case PID.TI_VIDEOTEX:
        key = "TI_VIDEOTEX";
        break;
        
      case PID.TI_TELETEX_CARRIER_UNSPECIFIED:
        key = "TI_TELETEX_CARRIER_UNSPECIFIED";
        break;
        
      case PID.TI_TELETEX_IN_PSPDN:
        key = "TI_TELETEX_IN_PSPDN";
        break;
        
      case PID.TI_TELETEX_IN_CSPDN:
        key = "TI_TELETEX_IN_CSPDN";
        break;
        
      case PID.TI_TELETEX_IN_ANALOG_PSTN:
        key = "TI_TELETEX_IN_ANALOG_PSTN";
        break;
        
      case PID.TI_TELETEX_IN_DIGITAL_ISDN:
        key = "TI_TELETEX_IN_DIGITAL_ISDN";
        break;
        
      case PID.TI_UNIVERSAL_COMPUTER_INTERFACE:
        key = "TI_UNIVERSAL_COMPUTER_INTERFACE";
        break;
        
      case PID.TI_RESERVED_01110:
      case PID.TI_RESERVED_01111:
        key = "TI_RESERVED";
        break;
        
      case PID.TI_MESSAGE_HANDLING_FACILITY:
        key = "TI_MESSAGE_HANDLING_FACILITY";
        break;
        
      case PID.TI_PUBLIC_X400_BASED_MESSAGE_HANDLING_SYSTEM:
        key = "TI_PUBLIC_X400_BASED_MESSAGE_HANDLING_SYSTEM";
        break;
        
      case PID.TI_INTERNET_ELECTRONIC_MAIL:
        key = "TI_INTERNET_ELECTRONIC_MAIL";
        break;
        
      case PID.TI_RESERVED_10011:
      case PID.TI_RESERVED_10100:
      case PID.TI_RESERVED_10101:
      case PID.TI_RESERVED_10110:
      case PID.TI_RESERVED_10111:
        key = "TI_RESERVED";
        break;
        
      case PID.TI_SC_SPECIFIC_11000:
      case PID.TI_SC_SPECIFIC_11001:
      case PID.TI_SC_SPECIFIC_11010:
      case PID.TI_SC_SPECIFIC_11011:
      case PID.TI_SC_SPECIFIC_11100:
      case PID.TI_SC_SPECIFIC_11101:
      case PID.TI_SC_SPECIFIC_11110:
        key = "TI_SC_SPECIFIC";
        break;
        
      case PID.TI_GSM_MOBILE_STATION:
        key = "TI_GSM_MOBILE_STATION";
        break;
      
      default:
        key = "TI_RESERVED";
        break;
      }
      break;
      
    case PID.GROUP_MT:
      switch (pid.getValue()) {
      case PID.MT_SHORT_MESSAGE_TYPE_0:
        key = "MT_SHORT_MESSAGE_TYPE_0";
        break;
        
      case PID.MT_REPLACE_SHORT_MESSAGE_TYPE_1:
        key = "MT_REPLACE_SHORT_MESSAGE_TYPE_1";
        break;
        
      case PID.MT_REPLACE_SHORT_MESSAGE_TYPE_2:
        key = "MT_REPLACE_SHORT_MESSAGE_TYPE_2";
        break;
        
      case PID.MT_REPLACE_SHORT_MESSAGE_TYPE_3:
        key = "MT_REPLACE_SHORT_MESSAGE_TYPE_3";
        break;
        
      case PID.MT_REPLACE_SHORT_MESSAGE_TYPE_4:
        key = "MT_REPLACE_SHORT_MESSAGE_TYPE_4";
        break;
        
      case PID.MT_REPLACE_SHORT_MESSAGE_TYPE_5:
        key = "MT_REPLACE_SHORT_MESSAGE_TYPE_5";
        break;
        
      case PID.MT_REPLACE_SHORT_MESSAGE_TYPE_6:
        key = "MT_REPLACE_SHORT_MESSAGE_TYPE_6";
        break;
        
      case PID.MT_REPLACE_SHORT_MESSAGE_TYPE_7:
        key = "MT_REPLACE_SHORT_MESSAGE_TYPE_7";
        break;
        
      case PID.MT_ENHANCED_MESSAGE_SERVICE:
        key = "MT_ENHANCED_MESSAGE_SERVICE";
        break;
        
      case PID.MT_RETURN_CALL_MESSAGE:
        key = "MT_RETURN_CALL_MESSAGE";
        break;
        
      case PID.MT_ANSI_136_R_DATA:
        key = "MT_ANSI_136_R_DATA";
        break;
        
      case PID.MT_DATA_DOWNLOAD:
        key = "MT_DATA_DOWNLOAD";
        break;
        
      case PID.MT_ME_DEPERSONALIZATION_SHORT_MESSAGE:
        key = "MT_ME_DEPERSONALIZATION_SHORT_MESSAGE";
        break;
        
      case PID.MT_SIM_DATA_DOWNLOAD:
        key = "MT_SIM_DATA_DOWNLOAD";
        break;
        
      default:
        key = "";
        break;
      }
      break;
      
    case PID.GROUP_RESERVED:
      key = "GROUP_RESERVED";
      break;
      
    case PID.GROUP_SC_SPECIFIC:
      key = "GROUP_SC_SPECIFIC";
      break;
      
    default:
      final int value = pid.getValue();
      /* MT values 8 to 30 are reserved */
      if (value >= 8 && value <= 30) {
        key = "GROUP_RESERVED";
      /* MT values 32 to 60 are reserved */
      } else if (value >= 32 && value <= 60) {
        key = "GROUP_RESERVED";
      } else {
        key = "GROUP_RESERVED";
      }
      break;
    }
    
    return getText(key, TP_PID);
  }
  
  public static String getSTText(final ST st) {
    final String key;
    final int value = st.getValue();
    switch (value) {
    case ST.SMTC_RECEIVED_BY_SME:
      key = "SMTC_RECEIVED_BY_SME";
      break;
      
    case ST.SMTC_FORWARDED_TO_SME:
      key = "SMTC_FORWARDED_TO_SME";
      break;
      
    case ST.SMTC_REPLACED_BY_SC:
      key = "SMTC_REPLACED_BY_SC";
      break;
      
    case ST.TEMP_RETRY_CONGESTION:
      key = "TEMP_RETRY_CONGESTION";
      break;
      
    case ST.TEMP_RETRY_SME_BUSY:
      key = "TEMP_RETRY_SME_BUSY";
      break;
      
    case ST.TEMP_RETRY_NO_RESPONSE_FROM_SME:
      key = "TEMP_RETRY_NO_RESPONSE_FROM_SME";
      break;
      
    case ST.TEMP_RETRY_SERVICE_REJECTED:
      key = "TEMP_RETRY_SERVICE_REJECTED";
      break;
      
    case ST.TEMP_RETRY_QOS_NOT_AVAILABLE:
      key = "TEMP_RETRY_QOS_NOT_AVAILABLE";
      break;
      
    case ST.TEMP_RETRY_ERROR_IN_SME:
      key = "TEMP_RETRY_ERROR_IN_SME";
      break;
      
    case ST.PERM_REMOTE_PROCEDURE_ERROR:
      key = "PERM_REMOTE_PROCEDURE_ERROR";
      break;
      
    case ST.PERM_INCOMPATIBLE_DESTINATION:
      key = "PERM_INCOMPATIBLE_DESTINATION";
      break;
      
    case ST.PERM_CONNECTION_REJECTED_BY_SME:
      key = "PERM_CONNECTION_REJECTED_BY_SME";
      break;
      
    case ST.PERM_NOT_OBTAINABLE:
      key = "PERM_NOT_OBTAINABLE";
      break;
      
    case ST.PERM_QOS_NOT_AVAILABLE:
      key = "PERM_QOS_NOT_AVAILABLE";
      break;
      
    case ST.PERM_NO_INTERWORKING_AVAILABLE:
      key = "PERM_NO_INTERWORKING_AVAILABLE";
      break;
      
    case ST.PERM_SM_VALIDITY_PERIOD_EXPIRED:
      key = "PERM_SM_VALIDITY_PERIOD_EXPIRED";
      break;
      
    case ST.PERM_DELETED_BY_ORIGINATING_SME:
      key = "PERM_DELETED_BY_ORIGINATING_SME";
      break;
      
    case ST.PERM_DELETED_BY_SC_ADMINISTRATION:
      key = "PERM_DELETED_BY_SC_ADMINISTRATION";
      break;
      
    case ST.PERM_SM_DOES_NOT_EXIST:
      key = "PERM_SM_DOES_NOT_EXIST";
      break;
      
    case ST.TEMP_CONGESTION:
      key = "TEMP_CONGESTION";
      break;
      
    case ST.TEMP_SME_BUSY:
      key = "TEMP_SME_BUSY";
      break;
      
    case ST.TEMP_NO_RESPONSE_FROM_SME:
      key = "TEMP_NO_RESPONSE_FROM_SME";
      break;
      
    case ST.TEMP_SERVICE_REJECTED:
      key = "TEMP_SERVICE_REJECTED";
      break;
      
    case ST.TEMP_QOS_NOT_AVAILABLE:
      key = "TEMP_QOS_NOT_AVAILABLE";
      break;
      
    case ST.TEMP_ERROR_IN_SME:
      key = "TEMP_ERROR_IN_SME";
      break;
      
    default:
      /* Values  3 to 15 reserved. */
      if (value >= 3 && value <= 15) {
        key = "RESERVED";
      /* Values 16 to 31 specific to each SC. */ 
      } else if (value >= 16 && value <= 31) {
        key = "SC_SPECIFIC";
      /* Values 38 to 47 reserved. */
      } else if (value >= 38 && value <= 47) {
        key = "RESERVED";
      /* Values 48 to 63 specific to each SC. */
      } else if (value >= 48 && value <= 63) {
        key = "SC_SPECIFIC";
      /* Values 74 to 79 reserved. */
      } else if (value >= 74 && value <= 79) {
        key = "RESERVED";
      /* Values 80 to 95 specific to each SC. */
      } else if (value >= 80 && value <= 95) {
        key = "SC_SPECIFIC";
      /* Values 102 to 105 reserved. */
      } else if (value >= 102 && value <= 105) {
        key = "RESERVED";
        /* Values 106 to 111 reserved. */
      } else if (value >= 106 && value <= 111) {
        key = "RESERVED";
        /* Values 112 to 127 specific to each SC. */
      } else if (value >= 112 && value <= 127) {
        key = "SC_SPECIFIC";
        /* Values 128 to 255 reserved. */
      } else if (value >= 128 && value <= 225) {
        key = "RESERVED";
      } else {
        key = "RESERVED";
      }
    }
    
    return getText(key, TP_ST);
  }
  
  public static String getFCSText(final FCS fcs) {
    final String key;
    final int value = fcs.getValue();
    switch (value) {
    case FCS.PID_TELEMATIC_INTERWORKING_NOT_SUPPORTED:
      key = "PID_TELEMATIC_INTERWORKING_NOT_SUPPORTED";
      break;
      
    case FCS.PID_SHORT_MESSAGE_TYPE_NOT_SUPPORTED:
      key = "PID_SHORT_MESSAGE_TYPE_NOT_SUPPORTED";
      break;
      
    case FCS.PID_CANNOT_REPLACE_SHORT_MESSAGE:
      key = "PID_CANNOT_REPLACE_SHORT_MESSAGE";
      break;
      
    case FCS.PID_UNSPECIFIED_ERROR:
      key = "PID_UNSPECIFIED_ERROR";
      break;
      
    case FCS.DCS_ALPHABET_NOT_SUPPORTED:
      key = "DCS_ALPHABET_NOT_SUPPORTED";
      break;
      
    case FCS.DCS_MESSAGE_CLASS_NOT_SUPPORTED:
      key = "DCS_MESSAGE_CLASS_NOT_SUPPORTED";
      break;
      
    case FCS.DCS_UNSPECIFIED_ERROR:
      key = "DCS_UNSPECIFIED_ERROR";
      break;
      
    case FCS.COMMAND_CANNOT_BE_ACTIONED:
      key = "COMMAND_CANNOT_BE_ACTIONED";
      break;
      
    case FCS.COMMAND_NOT_SUPPORTED:
      key = "COMMAND_NOT_SUPPORTED";
      break;
      
    case FCS.COMMAND_UNSPECIFIED_ERROR:
      key = "COMMAND_UNSPECIFIED_ERROR";
      break;
      
    case FCS.TPDU_NOT_SUPPORTED:
      key = "TPDU_NOT_SUPPORTED";
      break;
      
    case FCS.SC_BUSY:
      key = "SC_BUSY";
      break;
      
    case FCS.NO_SC_SUBSCRIPTION:
      key = "NO_SC_SUBSCRIPTION";
      break;
      
    case FCS.SC_SYSTEM_FAILURE:
      key = "SC_SYSTEM_FAILURE";
      break;
      
    case FCS.INVALID_SME_ADDRESS:
      key = "INVALID_SME_ADDRESS";
      break;
      
    case FCS.DESTINATION_SME_BARRED:
      key = "DESTINATION_SME_BARRED";
      break;
      
    case FCS.SM_REJECT_DUPLICATE_SM:
      key = "SM_REJECT_DUPLICATE_SM";
      break;
      
    case FCS.VPF_NOT_SUPPORTED:
      key = "VPF_NOT_SUPPORTED";
      break;
      
    case FCS.VP_NOT_SUPPORTED:
      key = "VP_NOT_SUPPORTED";
      break;
      
    case FCS.SIM_SMS_STORAGE_FULL:
      key = "SIM_SMS_STORAGE_FULL";
      break;
      
    case FCS.NO_SMS_STORAGE_CAPACITY_IN_SIM:
      key = "NO_SMS_STORAGE_CAPACITY_IN_SIM";
      break;
      
    case FCS.ERROR_IN_MS:
      key = "ERROR_IN_MS";
      break;
      
    case FCS.MEMORY_CAPACITY_EXCEEDED:
      key = "MEMORY_CAPACITY_EXCEEDED";
      break;
      
    case FCS.SIM_APPLICATION_TOOLKIT_BUSY:
      key = "SIM_APPLICATION_TOOLKIT_BUSY";
      break;
      
    case FCS.SIM_DATA_DOWNLOAD_ERROR:
      key = "SIM_DATA_DOWNLOAD_ERROR";
      break;
      
    case FCS.UNSPECIFIED_ERROR_CAUSE:
      key = "UNSPECIFIED_ERROR_CAUSE";
      break;
      
    default:
      /*  Errors 0 - 127 Reserved. */
      if (value >= 0 && value <= 127) {
        key = "RESERVED";
      /*  TP-PID errors 131 - 142 Reserved. */
      } else if (value >= 131 && value <= 142) {
        key = "PID_RESERVED_ERROR_CAUSE";
      /*  TP-DCS errors 146 - 158 Reserved. */
      } else if (value >= 146 && value <= 158) {
        key = "DCS_RESERVED_ERROR_CAUSE";
      /*  COMMAND errors 162 - 174 Reserved. */
      } else if (value >= 162 && value <= 174) {
        key = "COMMAND_RESERVED_ERROR_CAUSE";
      /*  Errors 177 - 191 Reserved. */
      } else if (value >= 177 && value <= 191) {
        key = "RESERVED";
      /*  Errors 200 - 207 Reserved. */
      } else if (value >= 200 && value <= 207) {
        key = "RESERVED";
      /*  Errors 214 - 223 Reserved. */
      } else if (value >= 214 && value <= 223) {
        key = "RESERVED";
      /*  Errors 224 - 254 Application specific. */
      } else if (value >= 224 && value <= 254) {
        key = "APPLICATION_SPECIFIC_ERROR_CAUSE";
      } else {
        key = "UNSPECIFIED_ERROR_CAUSE";
      }
    }
    
    return getText(key, TP_FCS);
  }
}
